package com.daisuxia.back.utils;

import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.RandomStringUtils;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.junit.Assert;
import org.xml.sax.InputSource;

/**
 *	金运通支付公司工具类
 */
public class JYTUtils {
//	@Autowired
//	private static IOutOrdersService outOrdersService;
	
	public static String RESP_MSG_PARAM_SEPARATOR = "&";
	/**返回报文merchant_id字段前缀*/
	public static String RESP_MSG_PARAM_PREFIX_MERCHANT_ID = "merchant_id=";
	/**返回报文xml_enc字段前缀*/
	public static String RESP_MSG_PARAM_PREFIX_XML_ENC = "xml_enc=";
	/**返回报文xml_enc字段前缀*/
	public static String RESP_MSG_PARAM_PREFIX_KEY_ENC = "key_enc=";
	/**返回报文sign字段前缀*/
	public static String RESP_MSG_PARAM_PREFIX_SIGN = "sign=";
	public static RSAHelper rsaHelper = new RSAHelper();
	public static JYTUtils webClient;

	public static JYTUtils getInstance() {
		if (webClient == null) {
			webClient = new JYTUtils();
		}
		return webClient;
	}
	/**
	 * 金运通实名认证(四要素)
	 * @param realName 	名字
	 * @param idNo 		身份证号
	 * @param phone 	手机号码
	 * @param cardNo 	银行卡号
	 * @return 
	 */
	public static Map<String, Object> JYTauth(Map<String, String> tokenParaMap,Logger logger) {
		try {
			rsaHelper.initKey(PropertiesUtil.get("CLIENT_PRIVATE_KEY"), PropertiesUtil.get("SERVER_PUBLIC_KEY"), 2048);
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		
		String userId = tokenParaMap.get("userId");//用户ID
		String cardNo = tokenParaMap.get("cardNo");//银行卡号
		String realName = tokenParaMap.get("actName");//姓名
		String phone = tokenParaMap.get("phone");//银行预留手机号码
		String idNo = tokenParaMap.get("idNo");//身份证号码
		String bankCode = tokenParaMap.get("bankCode");//银行id
		String tranCode =tokenParaMap.get("tranCode");//交易类型
		//固定参数
		String terminalType = "01";
		String bankCarkType = "D";// A C
		Map<String, Object> map = new HashMap<>();
		try {
			String xml = getSc0001Xml(tranCode,cardNo, bankCode, idNo, realName, terminalType, bankCarkType,phone);
			logger.info("request 金运通 param:"+xml);
			String mac = signMsg(xml);// 报文加签
			String respXml =JYTUtils.getInstance().sendMsg(xml, mac,logger);// 向服务器发送数据
			String respCode = getMsgRespCode(respXml);// 解析响应数据
			if("TR4004".equals(tranCode)) {
				String bindCardId = getMsgRespbindCardId(respXml);
				map.put("bindCardId", bindCardId);
			}else if("TR4003".equals(tranCode)){
				String bindBankName = getMsgRespbindBankName(respXml);//只有TR4003时才会返回
				map.put("bindBankName", bindBankName);
			}
			String msg = getMsgRespDesc(respXml);
			logger.info("响应信息： " + respXml);
			logger.info("返回响应码： " + respCode);
			
			/*OutOrders outOrders = new OutOrders();
			outOrders.setUserId(userId);
			outOrders.setOrderNo(bindCardId);
			outOrders.setAct("金运通获取验证码");
			outOrders.setReqParams(xml);
			outOrders.setReturnParams(respXml);
			outOrders.setStatus("2");
			outOrdersService.insertByTablelastName(outOrders);*/
			
			map.put("code", respCode);
			map.put("msg", msg);
			
		} catch (Exception e) {
			e.printStackTrace();
			map.put("code", "101");
		}
		return map;
	}
	/**
	 * 验证验证码是否正确
	 */
	public static Map<String, Object> JYTauthCode(String verifyCode,String phone, String bindCardId,String userId, Logger logger) throws Exception{
		try {
			rsaHelper.initKey(PropertiesUtil.get("CLIENT_PRIVATE_KEY"), PropertiesUtil.get("SERVER_PUBLIC_KEY"), 2048);
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		
		String xml= getSc0002Xml(PropertiesUtil.get("transactionCode"),bindCardId,verifyCode,phone);
		String mac=signMsg(xml);//报文加签
        String respXml = JYTUtils.getInstance().sendMsg(xml, mac, logger);//向服务器发送数据
        String respCode = getMsgRespCode(respXml);//解析响应数据
        String respDesc = getMsgRespDesc(respXml);
        System.out.println("响应信息： "+respXml);
        System.out.println("返回响应码： "+ respCode+",desc:"+respDesc);
        Map<String, Object> map = new HashMap<>();
        map.put("code", respCode);
        map.put("msg", respDesc);
        
        /*OutOrders outOrders = new OutOrders();
		outOrders.setUserId(userId);
		outOrders.setOrderNo(bindCardId+"验证");
		outOrders.setAct("金运通验证验证码是否正确");
		outOrders.setReqParams(xml);
		outOrders.setReturnParams(respXml);
		outOrders.setStatus("2");
		outOrdersService.insertByTablelastName(outOrders);*/
        
		return map;
	}
	
	
	/******************************************我******是******分******割******线******************************************************/
	
	
	
	
	/**
	 * 实名认证四要素
	 * <p> Create Date: 2014-5-10 </p>
	 * @return
	 */
	public static String getSc0001Xml(String tranCode,String bankCardNo,String bankCode,String idNum,String idName,String terminalType,String bankCarkType,String phone){
		StringBuffer xml = new StringBuffer();
		xml.append(getMsgHeadXml(tranCode));
		xml.append("<body><bank_card_no>").append(bankCardNo).append("</bank_card_no><bank_code>").append(bankCode).append("</bank_code>");
		xml.append("<id_num>").append(idNum).append("</id_num><id_name>").append(idName).append("</id_name>");
		xml.append("<terminal_type>").append(terminalType).append("</terminal_type>");
		xml.append("<bank_card_type>").append(bankCarkType).append("</bank_card_type>");
		xml.append("<phone_no>").append(phone).append("</phone_no>");
		xml.append("</body></message>");
		return xml.toString();
	}
	
	
	
	public static String signMsg(String xml){
		String hexSign = null ;
		try {
			byte[] sign = rsaHelper.signRSA(xml.getBytes("UTF-8"), false, "UTF-8") ;
			hexSign = StringUtil.bytesToHexString(sign) ;
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return hexSign;
	}
	
	/**
	 * 获得报文头字符串
	 * <p> Create Date: 2014-5-10 </p>
	 * @param tranCode
	 * @return
	 */
	public static String getMsgHeadXml(String tranCode){
		StringBuffer headXml = new StringBuffer();
		headXml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><message><head><version>1.0.0</version>");
		headXml.append("<tran_type>01</tran_type>")
			   .append("<merchant_id>").append(PropertiesUtil.get("MERCHANT_ID")).append("</merchant_id>");
		headXml.append("<tran_date>").append(DateTimeUtils.getNowDateStr(DateTimeUtils.DATE_FORMAT_YYYYMMDD))
		       .append("</tran_date>");
		headXml.append("<tran_time>").append(DateTimeUtils.getNowDateStr(DateTimeUtils.DATETIME_FORMAT_HHMMSS))
		       .append("</tran_time><tran_flowid>").append(getTranFlow())
		       .append("</tran_flowid><tran_code>").append(tranCode).append("</tran_code>");
		headXml.append("</head>");
		
		return headXml.toString();
	}
	/**
	 * 获取交易流水号
	 * <p> Create Date: 2014-5-10 </p>
	 * @return
	 */
	public static String getTranFlow(){
		return PropertiesUtil.get("MERCHANT_ID")+RandomStringUtils.randomNumeric(18);
	}
	public String sendMsg(String xml,String sign,Logger logger) throws Exception{
		byte[] des_key = DESHelper.generateDesKey() ;
		
		String merchant_id = PropertiesUtil.get("MERCHANT_ID");
		String encryptXml = JYTUtils.getInstance().encryptXml(xml,des_key);
		String encryptKey = JYTUtils.getInstance().encryptKey(des_key);
		
		Map<String,String> paramMap = new HashMap<String,String>();
		paramMap.put("merchant_id", merchant_id);
		paramMap.put("xml_enc",encryptXml);
		paramMap.put("key_enc", encryptKey);
		paramMap.put("sign", sign);
	
		// 获取执行结果
		String res = HttpClient431Util.doPost(paramMap, PropertiesUtil.get("APP_SERVER_URL"));
		
		if(res  == null){
			logger.error("服务器连接失败");
			throw new AppException("测试异常");
		}else{
			logger.info("连接服务器成功,返回结果"+res);
		}
		String []respMsg = res.split(RESP_MSG_PARAM_SEPARATOR);
		
		String merchantId = respMsg[0].substring(RESP_MSG_PARAM_PREFIX_MERCHANT_ID.length());
		String respXmlEnc = respMsg[1].substring(RESP_MSG_PARAM_PREFIX_XML_ENC.length());
		String respKeyEnc = respMsg[2].substring(RESP_MSG_PARAM_PREFIX_KEY_ENC.length());
		String respSign = respMsg[3].substring(RESP_MSG_PARAM_PREFIX_SIGN.length());
		
		byte respKey[] = decryptKey(respKeyEnc) ;
		String respXml = decrytXml( respXmlEnc,respKey ) ;
		
		Assert.assertTrue("返回报文校验失败",verifyMsgSign(respXml,respSign));
		
		return respXml;
	}

	private String encryptXml(String xml, byte[] key) {
		String enc_xml = CryptoUtils.desEncryptToHex(xml, key);
		return enc_xml;
	}

	private String encryptKey(byte[] key) {
		byte[] enc_key = null;
		try {
			enc_key = rsaHelper.encryptRSA(key, false, "UTF-8");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return StringUtil.bytesToHexString(enc_key);
	}
	private static byte[] decryptKey(String hexkey){
		byte[] key = null ;
		byte[] enc_key = StringUtil.hexStringToBytes(hexkey) ;
		
		try {
			key = rsaHelper.decryptRSA(enc_key, false, "UTF-8") ;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return key ;
	}
	public static String decrytXml(String xml_enc, byte[] key) {
		String xml = CryptoUtils.desDecryptFromHex(xml_enc, key) ;
		return xml;
	}
	public static boolean verifyMsgSign(String xml, String sign)
	{
		byte[] bsign = StringUtil.hexStringToBytes(sign) ;
		
		boolean ret = false ;
		try {
			ret = rsaHelper.verifyRSA(xml.getBytes("UTF-8"), bsign, false, "UTF-8") ;
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return ret;
	}
	public static String getMsgRespCode(String respMsg) throws Exception{
        SAXReader saxReader = new SAXReader();
		Document doc = saxReader.read(new InputSource(new StringReader(respMsg)));
		
		//解析报文头
		Node packageHead = doc.selectSingleNode("/message/head");
		
		Node respCodeNode = packageHead.selectSingleNode("resp_code");
		
		return respCodeNode.getText();
	}
	public static String getMsgRespDesc(String respMsg) throws Exception{
		SAXReader saxReader = new SAXReader();
		Document doc = saxReader.read(new InputSource(new StringReader(respMsg)));
		
		//解析报文头
		Node packageHead = doc.selectSingleNode("/message/head");
		
		Node respCodeNode = packageHead.selectSingleNode("resp_desc");
		
		return respCodeNode.getText();
	}
	public static String getMsgRespbindCardId(String respMsg) throws Exception{
		SAXReader saxReader = new SAXReader();
		Document doc = saxReader.read(new InputSource(new StringReader(respMsg)));
		
		Node respCodeNode = null;
		try {
			//解析报文头
			Node packageHead = doc.selectSingleNode("/message/body");
			respCodeNode = packageHead.selectSingleNode("bind_card_id");
		} catch (Exception e) {
			System.out.println("获取 bind_card_id 出现异常:"+respCodeNode);
			return "";
		}
		return respCodeNode.getText();
	}
	public static String getMsgRespbindBankName(String respMsg) throws Exception{
		SAXReader saxReader = new SAXReader();
		Document doc = saxReader.read(new InputSource(new StringReader(respMsg)));
		
		Node respCodeNode = null;
		try {
			//解析报文头
			Node packageHead = doc.selectSingleNode("/message/body");
			respCodeNode = packageHead.selectSingleNode("bank_name");
		} catch (Exception e) {
			System.out.println("获取 bind_card_id 出现异常:"+respCodeNode);
			return "";
		}
		return respCodeNode.getText();
	}
	
	
	
	public static String getSc0002Xml(String transactionCode,String bind_card_id,String verify_code,String phone_no){
		StringBuffer xml = new StringBuffer();
		xml.append(getMsgHeadXml(transactionCode));
		xml.append("<body><bind_card_id>").append(bind_card_id).append("</bind_card_id><verify_code>").append(verify_code).append("</verify_code>");
		xml.append("<phone_no>").append(phone_no).append("</phone_no>");
		xml.append("</body></message>");
		return xml.toString();
	}
}
